/* eslint-disable no-empty */
/**
 * 三维模型模块
 * @author hangzhou 2025-03-28
 */
import * as mars3d from "mars3d"
import { mapNoiseList, getMapNoiseTotal } from "@mars/api/data/index"
import { ref, watch } from "vue" 
import KDBush from "kdbush"
import { around } from "geokdbush"
import * as GeoTIFF from "geotiff"
import { handleMinioUrl } from "@mars/utils/minio"
import * as mapv from "mapv"
import * as turf from "@turf/turf"
const noisePath: string = import.meta.env.VITE_APP_NOISE_PATH as string

let map: mars3d.Map // 地图对象
let graphicLayer: mars3d.layer.GraphicLayer // 矢量图层
let arrLayer: any = []
const Cesium = mars3d.Cesium
// 初始化当前业务
export function onMounted(mapInstance: mars3d.Map): void {
  map = mapInstance // 记录map
  
  // 隐藏坐标
  map.control.locationBar.enabled = false // .LocationBar()

  map.setCameraView({ lat: 31.531747, lng: 120.730147, alt: 17769.2, heading: 359.9, pitch: -55.5 })

  // 加载常熟站点数据
  mars3d.Util.fetchJson({ 
    url: "http://124.71.130.201:40690/stations/map/391fe874067f431fb7262be4d680aa7c.json" 
  })
    .then(function (data) {
      console.log("========", data)
      if (data && data.features && data.features) {
        createChangshuPoints(data.features[0].geometry.coordinates[0])
      } else {
        console.error("数据格式不正确", data)
      }
    })
    .catch(function (error) {
      console.log("加载JSON出错", error)
    })
}

// 释放当前业务
export function onUnmounted(): void {

  // 隐藏坐标
  map.control.locationBar.enabled = true // .LocationBar()

  clearMapvLayers()

  // 删除时间控件
  map.removeControl(map.control.timeline)
  arrLayer.forEach((layer: any) => {

    // 清理事件监听
    if (layer._tileVisibleHandler) {
      layer.tileset?.tileVisible?.removeEventListener(layer._tileVisibleHandler)
    }

    // if (layer._hasRemoveLayer && layer.isAdded) {
      map.removeLayer(layer)
      layer._hasRemoveLayer = false
    // }
  })
  arrLayer = []
  map = null
}


// 配置常量
const DATA_CONFIG = ref({
  total: -1,
  pageSize: 10000,
  get totalPages() {
    return Math.ceil(this.total / this.pageSize)
  },
  time: "",
  concurrentLimit: 5,
  requestDelay: 200,
  maxRetry: 3,
  renderBatchSize: 10000, // 每加载多少条数据就渲染一次
  maxCacheTimes: 24, // 最大缓存时间点数（例如保存24小时历史数据）
  cacheExpiry: 3600_000 // 缓存过期时间（毫秒，可选）
})

// 状态管理
const noiseDataState = {
  isLoading: ref(false),
  progress: ref(0),
  loadedCount: ref(0),
  errorCount: ref(0),
  renderedCount: ref(0)
}

// 新增图层状态管理
const layerState = {
  isLayerReady: ref(false),
  layerLoadPromise: null as Promise<void> | null,
  layerResolver: null as (() => void) | null
}

// 数据存储
const listMapNoise = ref<any[]>([])
const noiseTimeCache = new Map<string, Map<string, number>>() // Map<timeKey, Map<coordKey, noiseValue>>
const pendingRenderData: any[] = [] // 待渲染数据队列

/**
 * 初始化图层加载状态
 */
function initLayerState() {
  layerState.layerLoadPromise = new Promise((resolve) => {
    layerState.layerResolver = resolve
  })
}

/**
 * 标记图层准备就绪
 */
function markLayerAsReady() {
  layerState.isLayerReady.value = true
  if (layerState.layerResolver) {
    layerState.layerResolver()
  }
}

// 单独封装获取单页数据的函数
async function fetchPageData(pageNum) {
  const res = await mapNoiseList({
    pageNum,
    pageSize: DATA_CONFIG.value.pageSize,
    time: DATA_CONFIG.value.time
  })
  return res.data.rows
}

// 获取当前日期的点位总数
async function getPageTotal() {
  const res = await getMapNoiseTotal({
    time: DATA_CONFIG.value.time
  })
  DATA_CONFIG.value.total = res.data
  return res.data
}

/**
 * 增量加载并渲染噪声数据
 */
export async function listAndRenderNoiseIncrementally(time, firstLoad = true) {
  /// 初始化状态
  noiseDataState.isLoading.value = true
  noiseDataState.progress.value = 0
  noiseDataState.loadedCount.value = 0
  noiseDataState.errorCount.value = 0
  noiseDataState.renderedCount.value = 0
  listMapNoise.value = []
  pendingRenderData.length = 0
  DATA_CONFIG.value.time = time
  processedTiles.clear()
  unProcessedTiles.clear()
  const layerId = "204013"
  // 检查缓存是否存在当前时间数据
  const cachedData = getCachedDataByTime(time)
  if (cachedData) {
    console.log(`使用缓存数据 [${time}]`, cachedData.length)
    await renderFromCache(cachedData, firstLoad, time, layerId)
    return
  }


  if (firstLoad) {
    initLayerState() // 只有首次加载需要初始化图层
  }

  try {
    // 非首次加载时直接标记图层就绪
    if (!firstLoad) {
      layerState.isLayerReady.value = true
    } else {
      // 首次加载才需要监控图层状态
      const layerLoadWatcher = watch(
        () => layerState.isLayerReady.value,
        (ready) => ready && processRenderQueue(true, time, layerId),
        { immediate: true }
      )
    }

    // 获取total总数
    const pageTotal = await getPageTotal()
    if (pageTotal === 0) {
       // 初始化图层事件监听
      //  onLayerLoaded("204013")
      updateNoiseValuesByLonLat(layerId, true).catch(console.error)
      return
    }

    // 加载数据（分页并发）
    const allPages = Array.from({ length: DATA_CONFIG.value.totalPages }, (_, i) => i + 1)
    
    while (allPages.length > 0) {
      const currentChunk = allPages.splice(0, DATA_CONFIG.value.concurrentLimit)
      
      const chunkPromises = currentChunk.map(page => 
        withRetry(() => fetchPageData(page), DATA_CONFIG.value.maxRetry)
          .catch(error => {
            console.error(`第 ${page} 页加载失败:`, error)
            noiseDataState.errorCount.value++
            return []
          })
      )

      const chunkResults = await Promise.allSettled(chunkPromises)
      
      // 处理成功数据
      const successfulData = chunkResults
      .filter(result => result.status === "fulfilled")
      .flatMap(result => (result as PromiseFulfilledResult<any[]>).value)
      
      pendingRenderData.push(...successfulData)
      noiseDataState.loadedCount.value += successfulData.length
      noiseDataState.progress.value = Math.round(
        (noiseDataState.loadedCount.value / DATA_CONFIG.value.total) * 100
      )

      // 非首次加载或图层已就绪时立即渲染
      if (!firstLoad || layerState.isLayerReady.value) {
        await processRenderQueue(false, time, layerId)
      }

      // 节流控制
      if (allPages.length > 0) {
        await sleep(DATA_CONFIG.value.requestDelay)
      }
    }

    // 确保剩余数据渲染（无论图层状态）
    await processRenderQueue(true, time, layerId)

    const layer = map.getLayerById(layerId)
    cleanupLayerEvents(layer)
    
  } catch (error) {
    console.error("加载噪声数据失败:", error)
  } finally {
    noiseDataState.isLoading.value = false
  }
}

/**
 * 处理渲染队列
 */
async function processRenderQueue(isFinal = false, time, layerId): Promise<void> {
  if (pendingRenderData.length === 0) { return }
  // 计算本次渲染量（最终批次处理全部剩余数据）
  const renderCount = isFinal 
    ? pendingRenderData.length 
    : Math.min(DATA_CONFIG.value.renderBatchSize, pendingRenderData.length)
  
  const renderData = pendingRenderData.splice(0, renderCount)
  
  // 更新数据状态
  listMapNoise.value = [...listMapNoise.value, ...renderData]
  noiseDataState.renderedCount.value += renderData.length

  // 直接使用现有地图实例渲染
  await updateMapDisplay(renderData, time, layerId)

  // 调试日志
  if (isFinal || noiseDataState.renderedCount.value % 100 === 0) {
    console.log(`渲染进度: ${noiseDataState.renderedCount.value}/${noiseDataState.loadedCount.value}`)
  }

  // 最终批次检查未处理瓦片
  if (isFinal) {
    retryUnprocessedTiles()
  }
}

/**
 * 更新地图显示
 */
function updateMapDisplay(newData: any[], time, layerId) {

  if (!newData.length) { return }
  // 1. 更新噪声值缓存
  updateNoiseValueCache(newData, time)

  // 2. 更新3D瓦片图层样式
  const layer = map.getLayerById(layerId)
  if (layer) {
    updateNoiseValuesByLonLat(layer.id).catch(console.error)
  }

}

/**
 * 从缓存渲染数据
 */
async function renderFromCache(cachedData: any[], firstLoad: boolean, time, layerId) {
  // 1. 拆分数据批次防止调用栈溢出
  const BATCH_SIZE = 20000
  for (let i = 0; i < cachedData.length; i += BATCH_SIZE) {
    // console.log("renderFromCach1111111=====", BATCH_SIZE)
    const batch = cachedData.slice(i, i + BATCH_SIZE)
    pendingRenderData.push(...batch)
    
    // 2. 更新状态（增量式）
    noiseDataState.loadedCount.value += batch.length
    noiseDataState.progress.value = Math.min(
      100,
      Math.round((noiseDataState.loadedCount.value / cachedData.length) * 100)
    )

    // 3. 确保每次循环都释放事件循环
    await new Promise(resolve => setTimeout(resolve, 0))
  }
  if (!firstLoad) {
    layerState.isLayerReady.value = true
    await processRenderQueue(true, time, layerId)
  } else {
    const unwatch = watch(
      () => layerState.isLayerReady.value,
      (ready) => {
        if (ready) {
          processRenderQueue(true, time, layerId)
          unwatch()
        }
      },
      { immediate: true }
    )
  }
}

/**
 * 获取当前时间缓存数据
 */
function getCachedDataByTime(time: string): any[] | null {
  const timeCache = noiseTimeCache.get(time)
  if (!timeCache) { return null }
  
  return Array.from(timeCache.entries()).map(([coordKey, value]) => ({
    lng: parseFloat(coordKey.split("_")[0]),
    lat: parseFloat(coordKey.split("_")[1]),
    noise: value
  }))
}

/**
 * 更新带时间维度的噪声缓存
 * @param data 噪声数据数组
 * @param time 时间标识（使用DATA_CONFIG.time格式）
 */
function updateNoiseValueCache(data: any[], time: string = DATA_CONFIG.value.time) {
  // 初始化该时间点的缓存（如果不存在）
  if (!noiseTimeCache.has(time)) {
    noiseTimeCache.set(time, new Map())
  }
  const timeCache = noiseTimeCache.get(time)!
  
  // 更新缓存
  data.forEach(item => {
    const coordKey = `${item.lng}_${item.lat}`
    timeCache.set(coordKey, item.noise)
  })

  // 缓存清理（可选）
  if (noiseTimeCache.size > DATA_CONFIG.value.maxCacheTimes) {
    const oldestKey = Array.from(noiseTimeCache.keys())[0]
    noiseTimeCache.delete(oldestKey)
  }
}

// 存储未处理的瓦片
const unProcessedTiles = new Map<object, { tile: any; lonLat: [number, number] }>()

// 存储已处理的瓦片（防止重复处理）
const processedTiles = new Set()

// 存储所有的瓦片，用于后续使用
const tilesMap = new Map<object, { tile: any; lonLat: [number, number] }>()
/**
 * 处理单个瓦片的噪声值设置
 */
function processTileWithRetry(tile: any, content: any) {
  const position = getAdjustedTileCenter(tile)
  if (!position) { return false }
  const { longitude, latitude } = toWGS84WithPrecision(position, 6)
  if (!longitude || !latitude) { return false }
  
  // 将瓦片加入map,供后续使用
  if (!tilesMap.has(tile)) { 
    tilesMap.set(tile, { tile, lonLat: [longitude, latitude] })
  }
  
  const matchedNoiseValue = findNearestNoiseValue(longitude, latitude, 0.0001)
 
  processTileFeatures(tile, content, matchedNoiseValue)
  if (matchedNoiseValue === undefined) { 
    unProcessedTiles.set(tile, { tile, lonLat: [longitude, latitude] })
  } else {
    processedTiles.add(tile)
    unProcessedTiles.delete(tile) // 移出未处理队列
  }

  return true
}

// 数据就绪检查函数
function isNoiseDataAvailable(lon: number, lat: number): boolean {
  // 实现方式1：检查点附近是否存在数据
  return findNearestNoiseValue(lon, lat, 0.0001) !== undefined

}

/**
 * 重试未处理的瓦片
 */
export function retryUnprocessedTiles() {
  let successCount = 0
  unProcessedTiles.forEach(({ tile, lonLat }, key) => {
    if (isNoiseDataAvailable(...lonLat)) {
      if (tile.content && processTileWithRetry(tile, tile.content)) {
        successCount++
      }
    }
  })
  console.log(`重试完成，成功处理 ${successCount} 个瓦片`)
}

/**
 * 动态设置图层图元的噪声值和颜色
 */

export async function updateNoiseValuesByLonLat(layerId: string, defFlg = false) {
  const layer = map.getLayerById(layerId)
  if (!layer) { return }
  await waitForLayerReady(layer)
  cleanupLayerEvents(layer)
  

  // 空数据特殊处理
  if (defFlg) {
    handleEmptyDataset(layer)
  } else {
    handleNormalData(layer)
  }

  
}

// 空数据处理逻辑
function handleEmptyDataset(layer: any) {
  noiseTimeCache.delete(DATA_CONFIG.value.time)
  // 1. 清除所有瓦片属性
  const handler = (tile: any) => {
      if (!tile.content) { return }
      
      const featuresLength = tile.content.featuresLength
      for (let i = 0; i < featuresLength; i++) {
          const feature = tile.content.getFeature(i)
          if (feature) {
              feature.setProperty("ZS0", 0) // 设为0值
              feature.featurePropertiesDirty = true
          }
      }
  }
  
  // 2. 立即执行一次全量更新
  layer.tileset.tileVisible.addEventListener(handler)
  layer._tileVisibleHandler = handler
  
  // 3. 设置空数据样式
  applyDynamicStyle(layer)
}

// 处理正常数据
function handleNormalData(layer: any) {
  let styleUpdateTimeout: NodeJS.Timeout

  const handler = (tile: any) => {
    // console.log("updateNoiseValuesByLonLat=============", processedTiles.has(tile))
    if (processedTiles.has(tile) || !tile.content) { return }
    
 
    if (!processTileWithRetry(tile, tile.content)) {
      return // 未处理的会自动加入unProcessedTiles
    }

    // 防抖样式更新
    clearTimeout(styleUpdateTimeout)
    styleUpdateTimeout = setTimeout(() => {
      applyDynamicStyle(layer)
      if (processedTiles.size > 100) { processedTiles.clear() }
    }, 150)
  }

  layer.tileset.tileVisible.addEventListener(handler)
  layer._tileVisibleHandler = handler
}

/**
 * 处理瓦片中的要素
 */
function processTileFeatures(tile: any, content: any, noiseValue: any) {
  
  const processedNoiseValue = noiseValue ?? 0
  // 批量处理特征
  const featuresLength = content.featuresLength
  for (let i = 0; i < featuresLength; i++) {
    const feature = content.getFeature(i)
    if (!feature) { continue }

    if (feature) {
      // console.log("processedNoiseValue=========", processedNoiseValue)
      feature.setProperty("ZS0", Number(processedNoiseValue))
      feature.featurePropertiesDirty = true
    }
  }
}

// 辅助函数
async function waitForLayerReady(layer: any): Promise<void> {
  return new Promise((resolve) => {
    const checkReady = () => {
      layer.tileset ? resolve() : setTimeout(checkReady, 100)
    }
    checkReady()
  })
}

function cleanupLayerEvents(layer: any): void {
  if (layer._tileVisibleHandler) {
    layer.tileset?.tileVisible?.removeEventListener(layer._tileVisibleHandler)
    delete layer._tileVisibleHandler
  }
}


/**
 * 带重试机制的请求封装
 */
async function withRetry<T>(fn: () => Promise<T>, maxRetry: number): Promise<T> {
  let attempt = 0
  while (attempt <= maxRetry) {
    try {
      return await fn()
    } catch (error) {
      if (attempt === maxRetry) { throw error }
      attempt++
      await sleep(1000 * attempt) // 指数退避
    }
  }
  throw new Error("Max retry reached")
}

export function flyToModel(layerId: string, center: any) {
  if (Array.isArray(layerId)) {
    layerId.forEach((element: any) => {
      const layer = map.getLayerById(element)
      if (layer) {
        arrLayer.push(layer)
      }
    })
  } else {
    const layer = map.getLayerById(layerId)
    if (layer) {
      arrLayer.push(layer)
    }
  }

  arrLayer.forEach((layer: any) => {
    if (!layer.isAdded) {
      map.addLayer(layer)
      layer._hasRemoveLayer = true
    }
    layer.show = true

  })

  if (center) {
    map.setCameraView(center)
  } 
}

/**
 * 应用动态样式并强制刷新
 */
function applyDynamicStyle(layer: any) {
  // 生成条件样式规则
  const conditions = [
    ["${ZS0} >= 110", "rgb(199,21,133)"],
    ["${ZS0} >= 90", "rgb(255,0,0)"],
    ["${ZS0} >= 70", "rgb(255,120,0)"],
    ["${ZS0} >= 50", "rgb(250,212,0)"],
    ["${ZS0} >= 30", "rgb(199,249,83)"],
    ["true", "rgb(0,255,81)"]
]
   // 4. 使用深拷贝强制更新
   const newStyle = new Cesium.Cesium3DTileStyle(JSON.parse(JSON.stringify({
    color: { conditions }
  })))

  layer.style = null
  setTimeout(() => {
    layer.style = newStyle
  }, 0)

}


// 辅助函数：延迟执行
function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms))
}

/**
 * 在图层加载完成后调用此方法
 */
export async function onLayerLoaded(layerId: string) {
  const layer = map.getLayerById(layerId)
  if (layer) {
    markLayerAsReady()
    // 初始化图层事件监听
    updateNoiseValuesByLonLat(layerId).catch(console.error)
  }
}



// ================ 工具函数 ================
/**
 * 获取经过transform矩阵调整后的瓦片中心
 */
function getAdjustedTileCenter(tile:any): any | null {
  try {
    const center = tile.boundingVolume.boundingVolume.center
    return center
  } catch (e) {
    console.warn("计算调整坐标失败:", e)
    return null
  }
}

/**
 * 高精度WGS84转换（可配置小数位）
 */
function toWGS84WithPrecision(
  position: any, 
  precision: number
): { longitude: number | null; latitude: number | null } {
  try {
    const cartographic = Cesium.Cartographic.fromCartesian(position)
    return {
          longitude: Cesium.Math.toDegrees(cartographic.longitude),
          latitude: Cesium.Math.toDegrees(cartographic.latitude)
    }
  } catch (e) {
    console.warn("坐标转换失败:", e)
    return { longitude: null, latitude: null }
  }
}


// 初始化
// 使用访问器模式
// 1. 准备数字数组
const points = Array.from(noiseTimeCache.entries()).filter(([timeKey]) => timeKey === DATA_CONFIG.value.time) // 先过滤出当前时间点
.flatMap(([_, coordMap]) => 
  Array.from(coordMap.entries()).map(([coordKey, value]) => ({
    lon: parseFloat(coordKey.split("_")[0]),
    lat: parseFloat(coordKey.split("_")[1]),
    value
  }))
)

// 2. 构建索引
const index = new KDBush(
  points,
  p => p.lon, // x坐标访问器
  p => p.lat // y坐标访问器
)

/**
 * 带容差的最近邻搜索
 */
function findNearestNoiseValue(
  lon: number, 
  lat: number, 
  tolerance: number
): number | undefined {

  const noiseValueCache = noiseTimeCache.get(DATA_CONFIG.value.time)
  // 2. 处理缓存未命中的情况
  if (noiseValueCache === undefined) {
    return undefined
  }
  // 方法1：精确匹配
  const exactKey = `${lon.toFixed(13)},${lat.toFixed(13)}`
  if (noiseValueCache.has(exactKey)) {
    return noiseValueCache.get(exactKey)
  }
  // 搜索最近点（0.01≈1.1km范围）
  const nearest = around(index, lon, lat, 1, tolerance)[0]
  // console.log("===========nearest", nearest, lon, lat)
  if (nearest) {
    return noiseValueCache.get(nearest[0].key)
  }

  // 方法3：线性搜索（小型数据集）
  let minDist = Infinity
  let result: number | undefined
  let lonX : number | undefined
  let lonY : number | undefined
  noiseValueCache.forEach((value, key) => {
    const [cacheLon, cacheLat] = key.split("_").map(Number)
    // if (cacheLon === 120.7349740145264) {
    //   console.log("cacheLon=========", cacheLon, value)
    // }
    const dist = Math.sqrt((lon - cacheLon) ** 2 + (lat - cacheLat) ** 2)
    if (dist < tolerance && dist < minDist) {
      minDist = dist
      result = value
      lonX = cacheLon
      lonY = cacheLat
    }
  })


  if (result === 100.00) {
    console.log("cacheLon=========", minDist, result)
  }
  // 输出结果
  // console.log("最近的缓存值:", result, "距离:", minDist, "经纬度", lonX, "-", lonY)
  return result
}

let tileLayer

export async function addTileLayer(originalData) {
  removeTileLayer()
  try {
    const originalUrl = handleMinioUrl("/stations/wgs84/" + originalData + ".tif")
    // const originalUrl = "https://file.hbkj-shs.com:9010/stations/map/zone/2025-01-01_20_00_00_zone_all_wgs84.tif"
    // const originalUrl = "https://file.hbkj-shs.com:9010/stations/map/zone/output7_wgs84.tif"
    // const originalUrl = " https://file.hbkj-shs.com:9010/stations/map/zone/output_4550_wgs84.tif"
    console.log("originalUrl＝＝＝＝＝＝", originalUrl)
    // const croppedResult = await cropTif(originalUrl)
    // 2. 根据噪声值设置颜色
    const result = await tif2img2(originalUrl)
    if (!result?.image || !result.extent) {
      console.error("无效的URL", originalUrl)
    }
    // 方式2：在创建地球后调用addLayer添加图层(直接new对应type类型的图层类)
    tileLayer = new mars3d.layer.ImageLayer({
      name: "常熟地图",
      url: result.image,
      rectangle: result.extent,
      crs: result.crs as mars3d.CRS,
      flyTo: true
    })

    map.addLayer(tileLayer)
  } catch (error) {
    console.error("加载或添加图层时出错", error)
    // 可以根据需要添加更多的错误处理逻辑，比如显示用户提示
  }
}

// 移除图层
export function removeTileLayer() {
  if (tileLayer) {
    map.removeLayer(tileLayer, true)
    tileLayer = null
  }
}

/**
 * 根据噪声值返回渐变色
 */
export function getColorByNoise(noiseValue: number): any {
  // if (noiseValue < 30) { return hexToRgb("#00FF51") }
  // if (noiseValue < 50) { return hexToRgb("#C7F953") }
  // if (noiseValue < 70) { return hexToRgb("#FAD400") }
  // if (noiseValue < 90) { return hexToRgb("#FF7800") }
  // if (noiseValue < 110) { return hexToRgb("#FF0000") }
  if (noiseValue >= 110) { return hexToRgb("#C71585") }
  if (noiseValue >= 90) { return hexToRgb("#FF0000") }
  if (noiseValue >= 70) { return hexToRgb("#FF7800") }
  if (noiseValue >= 50) { return hexToRgb("#FAD400") }
  if (noiseValue >= 30) { return hexToRgb("#C7F953") }
  return hexToRgb("#00FF51")
}

function hexToRgb(hex) {
  // 去除 # 号
  hex = hex.replace("#", "")
  
  // 解析为 R, G, B
  const r = parseInt(hex.substring(0, 2), 16)
  const g = parseInt(hex.substring(2, 4), 16)
  const b = parseInt(hex.substring(4, 6), 16)
  
  return [r, g, b]
  // return `rgb(${r}, ${g}, ${b})`
} 

// tif转换为图片， 使用了plotty库绘制（适合单通道+ 色带）
async function tif2img2(url) {
  const tif = await GeoTIFF.fromUrl(url)
  const image = await tif.getImage()

  // 取图片内容
  const [red, green, blue] = await image.readRasters()
  const width = image.getWidth()
  const height = image.getHeight()

  const canvas = mars3d.DomUtil.create("canvas")

  canvas.width = width
  canvas.height = height
  const ctx = canvas.getContext("2d")
  const imageData = ctx.createImageData(width, height)
  for (let i = 0; i < imageData.data.length / 4; i += 1) {
    const scolor = getColorByNoise(red[i])

    imageData.data[i * 4 + 0] = parseInt(scolor[0])
    imageData.data[i * 4 + 1] = parseInt(scolor[1]) || 0
    imageData.data[i * 4 + 2] = parseInt(scolor[2]) || 0
    imageData.data[i * 4 + 3] = 255

  }
  ctx.putImageData(imageData, 0, 0)

  // 范围及坐标系
  const [xmin, ymin, xmax, ymax] = image.getBoundingBox() // 矩形范围
  let extent = { xmin, ymin, xmax, ymax }
  const code = image.geoKeys.ProjectedCSTypeGeoKey || image.geoKeys.GeographicTypeGeoKey // 坐标系
  const crs = "EPSG:" + code
  if (crs && crs !== mars3d.CRS.EPSG4326 && crs !== mars3d.CRS.EPSG4490) {
    const ptMin = mars3d.PointTrans.proj4Trans([extent.xmin, extent.ymin], crs)
    const ptMax = mars3d.PointTrans.proj4Trans([extent.xmax, extent.ymax], crs)
    extent = { xmin: ptMin[0], ymin: ptMin[1], xmax: ptMax[0], ymax: ptMax[1] }
  }

  return {
    image: canvas.toDataURL("image/png"),
    extent,
    crs
  }
}

/**
 * 裁切TIF图像
 * @param url TIF文件URL
 * @param bbox 裁切范围 [minX, minY, maxX, maxY]
 */
export async function cropTif(url: string, bbox: number[]) {
  // 1. 加载TIF文件
  const tif = await GeoTIFF.fromUrl(url)
  const image = await tif.getImage()
  
  // 2. 获取原始图像信息
  const [minX, minY, maxX, maxY] = image.getBoundingBox()
  const width = image.getWidth()
  const height = image.getHeight()
  
  // 3. 计算裁切范围在图像中的像素位置
  const pixelLeft = Math.floor((bbox[0] - minX) / (maxX - minX) * width)
  const pixelTop = Math.floor((maxY - bbox[3]) / (maxY - minY) * height)
  const pixelRight = Math.floor((bbox[2] - minX) / (maxX - minX) * width)
  const pixelBottom = Math.floor((maxY - bbox[1]) / (maxY - minY) * height)
  
  const cropWidth = pixelRight - pixelLeft
  const cropHeight = pixelBottom - pixelTop
  
  // 4. 安全读取裁切区域的栅格数据
  const rasters = await image.readRasters({
    window: [pixelLeft, pixelTop, pixelRight, pixelBottom],
    width: cropWidth,
    height: cropHeight
  })

  // 确保获取到的是TypedArray数据
  const rasterData = Array.isArray(rasters) 
    ? (rasters[0] as Uint8Array | Uint16Array | Float32Array)
    : (rasters as Uint8Array | Uint16Array | Float32Array)

  if (!rasterData || !rasterData.length) {
    throw new Error("未能获取有效的栅格数据")
  }
  
  // 5. 创建裁切后的Canvas
  const canvas = document.createElement("canvas")
  canvas.width = cropWidth
  canvas.height = cropHeight
  const ctx = canvas.getContext("2d")
  const imageData = ctx.createImageData(cropWidth, cropHeight)
  
  // 6. 填充裁切后的图像数据
  for (let i = 0; i < rasterData.length; i++) {
    imageData.data[i * 4] = rasterData[i] // R
    imageData.data[i * 4 + 1] = rasterData[i] // G
    imageData.data[i * 4 + 2] = rasterData[i] // B
    imageData.data[i * 4 + 3] = 255 // Alpha
  }
  
  ctx.putImageData(imageData, 0, 0)
  
  // 7. 返回裁切后的图像和范围
  return {
    image: canvas.toDataURL("image/png"),
    extent: { xmin: bbox[0], ymin: bbox[1], xmax: bbox[2], ymax: bbox[3] },
    crs: "EPSG:" + (image.geoKeys.ProjectedCSTypeGeoKey || image.geoKeys.GeographicTypeGeoKey)
  }
}

// 存储图层引用，方便后续清除
let mapvLayers = []

// 创建常熟市区内的随机点
function createChangshuPoints(stationsData) {
  console.log("stationsData====", stationsData)
  
  // 先清除已有图层
  clearMapvLayers()
  
  // 过滤出常熟三环内的站点（假设数据中有区域标识或坐标范围）
  // 这里简化处理，直接从数据中取前3个点
  const selectedPoints = [
    { stationName: "桃花岛", longitude: "120.677211", latitude: "31.649693" },
    { stationName: "第一中学", longitude: "120.711454", latitude: "31.625941" },
    { stationName: "体育中心", longitude: "120.777374", latitude: "31.658102" }
  ]

  // 创建连接线数据和飞行动画数据
  const lineData = []
  const timeData = [] // 用于飞行动画的数据
  
  if (selectedPoints.length > 1) {
    for (let i = 0; i < selectedPoints.length - 1; i++) {
      const startPoint = [parseFloat(selectedPoints[i].longitude), parseFloat(selectedPoints[i].latitude)]
      const endPoint = [parseFloat(selectedPoints[2].longitude), parseFloat(selectedPoints[2].latitude)]
      
      // 生成曲线上的点（确保连线和飞行路线一致）
      const curvePoints = mapv.utilCurve.getPoints([
        { lng: startPoint[0], lat: startPoint[1] },
        { lng: endPoint[0], lat: endPoint[1] }
      ])
      
      // 1. 使用相同的曲线创建静态连接线
      lineData.push({
        geometry: {
          type: "LineString",
          coordinates: curvePoints // 使用曲线点而不是直线
        },
        count: 30 * Math.random(),
        color: "rgba(255, 50, 50, 0.5)"
      })
      
      // 2. 飞行动画数据使用相同的曲线点
      for (let j = 0; j < curvePoints.length; j++) {
        // 创建从深红到亮红的渐变效果
        const redIntensity = Math.floor(150 + (j / curvePoints.length) * 105)
        timeData.push({
          geometry: {
            type: "Point",
            coordinates: curvePoints[j]
          },
          count: 1,
          time: j,
          size: 3, // 稍微增大点大小
          color: `rgba(255, ${redIntensity}, ${redIntensity}, 0.9)` // 红色系
        })
      }
    }
  }
  
  // 准备点数据
  const pointData = selectedPoints.map(station => {
    return {
      geometry: {
        type: "Point",
        coordinates: [parseFloat(station.longitude), parseFloat(station.latitude)]
      },
      properties: {
        name: station.stationName || "监测点",
        value: Math.random() * 100 // 随机值
      },
      color: "rgba(200, 30, 30, 0.8)" // 深红色
    }
  })

  // 准备文本标注数据
  const textData = selectedPoints.map(station => {
    return {
      geometry: {
        type: "Point",
        coordinates: [parseFloat(station.longitude), parseFloat(station.latitude)]
      },
      text: station.stationName || "监测点"
    }
  })

  // 1. 创建点图层
  const pointOptions = {
    fillStyle: "rgba(44, 42, 38, 0.7)",
    shadowColor: "rgba(55, 50, 250, 0.5)",
    shadowBlur: 10,
    size: 15, // 点大小
    zIndex: 10,
    draw: "simple",
    data: pointData
  }
  const pointLayer = new mars3d.layer.MapVLayer(pointOptions)
  map.addLayer(pointLayer)
  mapvLayers.push(pointLayer)

  // 2. 创建文本标注图层
  const textOptions = {
    draw: "text",
    font: "14px Arial",
    fillStyle: "white",
    shadowColor: "yellow",
    shadowBlur: 10,
    zIndex: 11,
    data: textData
  }
  const textLayer = new mars3d.layer.MapVLayer(textOptions)
  map.addLayer(textLayer)
  mapvLayers.push(textLayer)

  // 3. 创建静态连接线图层（使用曲线路径）
  if (lineData.length > 0) {
    const lineOptions = {
      strokeStyle: "rgba(255, 50, 50, 0.5)", // 红色半透明
      shadowColor: "rgba(255, 80, 80, 0.6)", // 亮红色阴影
      shadowBlur: 10,
      lineWidth: 2,
      zIndex: 99, // 在动画点之下
      draw: "simple",
      data: lineData
    }
    const lineLayer = new mars3d.layer.MapVLayer(lineOptions)
    map.addLayer(lineLayer)
    mapvLayers.push(lineLayer)
  }

  // 4. 创建飞行动画图层（使用相同的曲线路径）
  if (timeData.length > 0) {
    const timeOptions = {
      fillStyle: "rgba(255, 100, 100, 0.9)", // 亮红色
      zIndex: 100,
      size: 2,
      animation: {
        type: "time", // 时间动画类型
        stepsRange: { // 动画时间范围
          start: 0,
          end: 100
        },
        trails: 10, // 拖尾效果长度
        duration: 5, // 动画持续时间(秒)
        delay: 2 // 延迟开始时间(秒)
      },
      draw: "simple",
      data: timeData
    }
    const flyLayer = new mars3d.layer.MapVLayer(timeOptions)
    map.addLayer(flyLayer)
    mapvLayers.push(flyLayer)
    
    // 添加循环播放功能
    let animationInterval
    const restartAnimation = () => {
      if (animationInterval) { clearInterval(animationInterval) }
      
      // 每7秒重新播放一次动画（5秒动画+2秒延迟）
      animationInterval = setInterval(() => {
        flyLayer.options.animation.delay = 0 // 后续循环不需要延迟
        flyLayer.draw()
      }, 7000)
    }
    
    // 初始延迟后开始循环
    setTimeout(restartAnimation, 2000)
    
    // 图层移除时清除定时器
    flyLayer.on(mars3d.EventType.remove, () => {
      clearInterval(animationInterval)
    })
  }
}

// 清除所有MapV图层
function clearMapvLayers() {
  mapvLayers.forEach(layer => {
    if (layer && !layer.isDestroyed) {
      map.removeLayer(layer)
    }
  })
  mapvLayers = []
}

// 图层管理对象
export const layerManager = {
  currentLayer: null as mars3d.layer.ImageLayer | null,
  
  /**
   * 添加并显示TIF图层
   * @param originalData 图层数据或URL
   * @param options 配置选项
   */
  async addTileLayer(originalData: string, options: {
    cropWithGeoJSON?: string;
    colorMap?: (value: number) => number[];
    flyTo?: boolean;
  } = {}) {
    this.removeCurrentLayer()
    
    try {
      // 1. 准备图层URL
      const originalUrl = this.prepareLayerUrl(originalData)
      
      // 2. 获取图像数据
      const result = options.cropWithGeoJSON 
        ? await this.cropTifWithGeoJSON(originalUrl, options.cropWithGeoJSON)
        : await this.tifToImage(originalUrl, options.colorMap)
      
      if (!result?.image || !result.extent) {
        throw new Error("获取图像数据失败")
      }

      // 3. 创建并添加图层
      this.currentLayer = new mars3d.layer.ImageLayer({
        name: "动态地图图层",
        url: result.image,
        rectangle: this.adjustExtent(result.extent), // 边缘调整
        crs: result.crs as mars3d.CRS,
        flyTo: options.flyTo ?? true,
        alpha: 0.9 // 添加透明度
      })

      map.addLayer(this.currentLayer)
      
      // 4. 添加边缘遮罩
      if (options.cropWithGeoJSON) {
        this.addCropMask(options.cropWithGeoJSON)
      }
      
    } catch (error) {
      console.error("图层加载失败:", error)
      throw error
    }
  },
  
  /**
   * 移除当前图层
   */
  removeCurrentLayer() {
    if (this.currentLayer) {
      map.removeLayer(this.currentLayer)
      this.currentLayer = null
      this.removeCropMask()
    }
  },
  
  /**
   * 准备图层URL
   */
  prepareLayerUrl(data: string): string {
    // 这里可以添加URL处理逻辑
    return data.startsWith("http") || data.startsWith("https") ? data : handleMinioUrl(noisePath + data + ".tif")
  },
  
  /**
   * 调整范围边界
   */
  adjustExtent(extent: { xmin: number; ymin: number; xmax: number; ymax: number }) {
    // 添加1%的边界缓冲
    const buffer = 0.01
    const width = extent.xmax - extent.xmin
    const height = extent.ymax - extent.ymin
    
    return {
      xmin: extent.xmin - width * buffer,
      ymin: extent.ymin - height * buffer,
      xmax: extent.xmax + width * buffer,
      ymax: extent.ymax + height * buffer
    }
  },
  
  /**
   * 添加裁剪遮罩
   */
  async addCropMask(geojsonUrl: string) {
    try {
      const geojson = await mars3d.Util.fetchJson({ url: geojsonUrl })
      map.addLayer(new mars3d.layer.GeoJsonLayer({
        name: "裁剪遮罩",
        data: geojson,
        symbol: {
          type: "polygon",
          styleOptions: {
            color: "#000",
            opacity: 0,
            outline: false,
            outlineColor: "#fff",
            outlineWidth: 0
          }
        },
        flyTo: false
      }))
    } catch (error) {
      console.warn("无法添加裁剪遮罩:", error)
    }
  },
  
  /**
   * 移除裁剪遮罩
   */
  removeCropMask() {
    const maskLayer = map.getLayer("裁剪遮罩")
    if (maskLayer) {
      map.removeLayer(maskLayer)
    }
  },
  
  /**
   * TIF转图像
   */
  async tifToImage(url: string, colorMap?: (value: number) => number[]) {
    const tif = await GeoTIFF.fromUrl(url)
    const image = await tif.getImage()
    const [red] = await image.readRasters() // 只读取红色通道
    
    const canvas = mars3d.DomUtil.create("canvas")
    canvas.width = image.getWidth()
    canvas.height = image.getHeight()
    const ctx = canvas.getContext("2d")
    const imageData = ctx.createImageData(canvas.width, canvas.height)
    
    // 使用默认或自定义颜色映射
    const getColor = colorMap || this.defaultColorMap
    
    for (let i = 0; i < imageData.data.length / 4; i++) {
      const color = getColor(red[i])
      imageData.data.set(color, i * 4)
      imageData.data[i * 4 + 3] = 255 // Alpha通道
    }
    
    ctx.putImageData(imageData, 0, 0)
    
    // 处理坐标范围和CRS
    const [xmin, ymin, xmax, ymax] = image.getBoundingBox()
    const code = image.geoKeys.ProjectedCSTypeGeoKey || image.geoKeys.GeographicTypeGeoKey
    const crs = "EPSG:" + code
    
    return {
      image: canvas.toDataURL("image/png"),
      extent: { xmin, ymin, xmax, ymax },
      crs
    }
  },
  
  /**
   * 默认颜色映射
   */
  defaultColorMap(value: number): number[] {
    if (value >= 110) { return [199, 21, 133] } // #C71585
    if (value >= 90) { return [255, 0, 0] } // #FF0000
    if (value >= 70) { return [255, 120, 0] } // #FF7800
    if (value >= 50) { return [250, 212, 0] } // #FAD400
    if (value >= 30) { return [199, 249, 83] } // #C7F953
    return [0, 255, 81] // #00FF51
  },
  
    /**
     * 使用GeoJSON裁剪TIF
     */
  async  cropTifWithGeoJSON(url: string, geojsonUrl: string, colorMap?: (value: number) => number[]): Promise<any> {
    // 1. 获取并解析GeoJSON数据
    let geometry
    try {
      const geojson = await mars3d.Util.fetchJson({ url: geojsonUrl })
      
      // 更健壮的geometry提取逻辑
      if (!geojson || !geojson.type) {
        throw new Error("无效的GeoJSON数据")
      }

      if (geojson.type === "FeatureCollection") {
        if (!geojson.features || geojson.features.length === 0) {
          throw new Error("FeatureCollection中未包含任何要素")
        }
        geometry = geojson.features[0].geometry
      } else if (geojson.type === "Feature") {
        geometry = geojson.geometry
      } else if (geojson.type === "GeometryCollection") {
        throw new Error("暂不支持GeometryCollection类型")
      } else {
        geometry = geojson
      }
    } catch (error) {
      throw new Error(`获取或解析GeoJSON失败: ${error}`)
    }

    // 验证几何类型
    if (!geometry || !["Polygon", "MultiPolygon"].includes(geometry.type)) {
      throw new Error("只支持Polygon或MultiPolygon类型的GeoJSON")
    }

    // 2. 加载TIF文件
    const tif = await GeoTIFF.fromUrl(url)
    const image = await tif.getImage()
    const [imageMinX, imageMinY, imageMaxX, imageMaxY] = image.getBoundingBox()
    const imageWidth = image.getWidth()
    const imageHeight = image.getHeight()

    // 3. 计算精确裁剪边界
    const geojsonBbox = turf.bbox(geometry)
    let [minX, minY, maxX, maxY] = geojsonBbox
    
    // 边界安全处理
    minX = Math.max(minX, imageMinX)
    minY = Math.max(minY, imageMinY)
    maxX = Math.min(maxX, imageMaxX)
    maxY = Math.min(maxY, imageMaxY)

    // 4. 计算像素范围 (添加1像素缓冲避免边缘问题)
    const pixelLeft = Math.max(0, Math.floor((minX - imageMinX) / (imageMaxX - imageMinX) * imageWidth) - 1)
    const pixelTop = Math.max(0, Math.floor((imageMaxY - maxY) / (imageMaxY - imageMinY) * imageHeight) - 1)
    const pixelRight = Math.min(imageWidth, Math.ceil((maxX - imageMinX) / (imageMaxX - imageMinX) * imageWidth) + 1)
    const pixelBottom = Math.min(imageHeight, Math.ceil((imageMaxY - minY) / (imageMaxY - imageMinY) * imageHeight) + 1)

    const cropWidth = pixelRight - pixelLeft
    const cropHeight = pixelBottom - pixelTop

    if (cropWidth <= 0 || cropHeight <= 0) {
      throw new Error("裁剪区域无效")
    }

    // 5. 分块读取栅格数据 (避免内存溢出)
    const rasters: any = await image.readRasters({
      window: [pixelLeft, pixelTop, pixelRight, pixelBottom],
      width: cropWidth,
      height: cropHeight,
      interleave: true // 获取交错排列的RGB数据
    })

    // 6. 创建Canvas
    const canvas = document.createElement("canvas")
    canvas.width = cropWidth
    canvas.height = cropHeight
    const ctx = canvas.getContext("2d", { willReadFrequently: true })
    if (!ctx) { throw new Error("无法获取Canvas上下文") }

    // 7. 创建并填充图像数据
    const imageData = ctx.createImageData(cropWidth, cropHeight)
    const coords = geometry.type === "Polygon" ? [geometry.coordinates] : geometry.coordinates

    // 预计算所有多边形路径
    const paths = coords.map((polygon: any[][]) => {
      return polygon.map((ring: any[]) => {
        return ring.map(([x, y]: [number, number]) => {
          const px = ((x - imageMinX) / (imageMaxX - imageMinX) * imageWidth) - pixelLeft
          const py = ((imageMaxY - y) / (imageMaxY - imageMinY) * imageHeight) - pixelTop
          return [px, py] as [number, number]
        })
      })
    })

    // 8. 填充像素数据
  
    const getColor = colorMap || this.defaultColorMap
  
    // 9. 统一像素处理方式
    const rasterData = await image.readRasters({
      window: [pixelLeft, pixelTop, pixelRight, pixelBottom],
      width: cropWidth,
      height: cropHeight
    })

    // 获取单通道数据（与tifToImage保持一致）
    const values = Array.isArray(rasters) ? rasters[0] : rasters

    // 创建透明背景
    
    for (let y = 0; y < cropHeight; y++) {
      for (let x = 0; x < cropWidth; x++) {
        const i = y * cropWidth + x
        const pixelIndex = i * 4
        const pixelPos: [number, number] = [x + 0.5, y + 0.5]

        // 检查是否在裁剪区域内
        const isInside = paths.some(polygon => 
          polygon.some(ring => isPointInRing(pixelPos, ring))
        )

        if (isInside) {
          // 统一使用单通道值+颜色映射（与tifToImage相同逻辑）
          const value = values[i]
          const [r, g, b] = getColor(value)
          
          imageData.data[pixelIndex] = r
          imageData.data[pixelIndex + 1] = g
          imageData.data[pixelIndex + 2] = b
          imageData.data[pixelIndex + 3] = 255
        } else {
          // 区域外透明处理
          imageData.data[pixelIndex + 3] = 0
        }
      }
    }

    // 10. 统一输出格式
    ctx.putImageData(imageData, 0, 0)

    return {
      image: canvas.toDataURL("image/png"),
      extent: { xmin: minX, ymin: minY, xmax: maxX, ymax: maxY },
      crs: "EPSG:" + (image.geoKeys?.ProjectedCSTypeGeoKey || image.geoKeys?.GeographicTypeGeoKey || "4326"),
      transparent: true // 明确标记为透明
    }
  }
}


// 高性能的点在多边形内检测 (射线法)
function isPointInRing(point: [number, number], ring: [number, number][]): boolean {
  let inside = false
  const [x, y] = point
  
  for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
    const [xi, yi] = ring[i]
    const [xj, yj] = ring[j]
    
    const intersect = ((yi > y) !== (yj > y)) &&
      (x < (xj - xi) * (y - yi) / (yj - yi) + xi)
    if (intersect) { inside = !inside }
  }
  
  return inside
}
